package org.xiaov.lunasql.engine.ast.adjust;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import org.xiaov.lunasql.engine.ast.LimitAdjust;
import org.xiaov.lunasql.engine.transform.oracle.OracleConstant;

/**
 * <p>
 * Limit
 * </p>
 *
 * @author LunaSQL
 * @since 2024/12/11 23:48
 */
public class Limit2RowNumAdjust implements LimitAdjust {

    @Override
    public void adjust(SQLLimit x) {
        SQLObject parent = x.getParent();
        if ((x.getOffset() == null && x.getBy() == null)
                || ((x.getOffset() instanceof SQLNumericLiteralExpr offset) && offset.getNumber().intValue() == 0)) {
            // limit x  limit x offset 0 等效与 limit x
            SQLExpr rowCount = x.getRowCount();
            if (parent instanceof SQLSelectQueryBlock selectQueryBlock) {
                selectQueryBlock.setLimit(null);
                selectQueryBlock.addWhereForDynamicFilter(new SQLBinaryOpExpr(new SQLIdentifierExpr(OracleConstant.ROWNUM), SQLBinaryOperator.LessThanOrEqual, rowCount));
            }
        } else if (x.getOffset() != null) {
            if (parent instanceof SQLSelectQueryBlock selectQueryBlock) {
                // limit x offset y
                selectQueryBlock.setLimit(null);
                SQLObject grandParent = parent.getParent();
                if (grandParent instanceof SQLSelect select) {
                    //原始sql
                    SQLSelect selectOrigin = new SQLSelect();
                    selectOrigin.setQuery(selectQueryBlock);
                    int offset = Integer.parseInt(x.getOffset().toString());
                    int rowcount = Integer.parseInt(x.getRowCount().toString());

                    //内层循环
                    SQLSubqueryTableSource subqueryTableSource = new SQLSubqueryTableSource(selectOrigin, "LUNA");
                    SQLSelectQueryBlock selectQueryBlockLuna = new SQLSelectQueryBlock();
                    selectQueryBlockLuna.setFrom(subqueryTableSource);
                    selectQueryBlockLuna.addSelectItem(new SQLSelectItem(new SQLIdentifierExpr(OracleConstant.ROWNUM), "ROW_ID"));
                    selectQueryBlockLuna.addSelectItem(new SQLSelectItem(new SQLIdentifierExpr("LUNA.*")));
                    selectQueryBlockLuna.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr(OracleConstant.ROWNUM),
                            SQLBinaryOperator.LessThanOrEqual, new SQLNumberExpr(offset + rowcount)));

                    //外层循环
                    SQLSelect selectLuna = new SQLSelect();
                    selectLuna.setQuery(selectQueryBlockLuna);
                    SQLSubqueryTableSource subqueryTableSourceLuna = new SQLSubqueryTableSource(selectLuna, "LUNA");

                    SQLSelectQueryBlock selectQueryBlockLunaOuter = new SQLSelectQueryBlock();
                    selectQueryBlockLunaOuter.addSelectItem(new SQLSelectItem(new SQLAllColumnExpr()));
                    selectQueryBlockLunaOuter.setFrom(subqueryTableSourceLuna);
                    selectQueryBlockLunaOuter.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("ROW_ID"),
                            SQLBinaryOperator.GreaterThanOrEqual, x.getRowCount()));
                    select.setQuery(selectQueryBlockLunaOuter);
                }
            }
        }
    }

}
